package bim

import (
	"bytes"
	"fmt"
	"cgs-server/helper"
	"cgs-server/server"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"cgs-server/server/service"
	"cgs-server/server/store"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"strings"
)

type BimHandler struct {
	// srv service
	srv service.Service
	// store
	store store.Factory
}

func NewBimHandler(store store.Factory) *BimHandler {
	return &BimHandler{
		srv: service.NewService(store),
		store: store,
	}
}

// UploadFileToOss 上传文件到阿里云，临时接口，之后会弃用
func (b *BimHandler) UploadFileToOss(w http.ResponseWriter, r *http.Request) {
	err := r.ParseMultipartForm(100 << 20)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	file := r.MultipartForm.File["file"][0]
	originFile, err := file.Open()
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	defer originFile.Close()

	name := r.FormValue("name")
	key := r.FormValue("key")
	policy := r.FormValue("policy")
	OSSAccessKeyId := r.FormValue("OSSAccessKeyId")
	callback := r.FormValue("callback")
	signature := r.FormValue("signature")
	success_action_status := r.FormValue("success_action_status")
	host := r.FormValue("host")


	bodyBuf := &bytes.Buffer{}
	bodyWriter := multipart.NewWriter(bodyBuf)

	err = bodyWriter.WriteField("name", name)
	err = bodyWriter.WriteField("key", key)
	err = bodyWriter.WriteField("policy", policy)
	err = bodyWriter.WriteField("OSSAccessKeyId", OSSAccessKeyId)
	err = bodyWriter.WriteField("callback", callback)
	err = bodyWriter.WriteField("signature", signature)
	err = bodyWriter.WriteField("success_action_status", success_action_status)

	formFileWriter, err := bodyWriter.CreateFormFile("file", name)
	if _, err := io.Copy(formFileWriter, originFile); err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	contentType := bodyWriter.FormDataContentType()
	err = bodyWriter.Close()
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	response, err := http.Post(host, contentType, bodyBuf)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	defer response.Body.Close()

	respBody, err := ioutil.ReadAll(response.Body)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	_, err = w.Write(respBody)

}

// UploadFile 上传模型文件
func (b *BimHandler) UploadFile(w http.ResponseWriter, r *http.Request) {
	err := r.ParseMultipartForm(100 << 20)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	file := r.MultipartForm.File["file"][0]
	user, err := base.GetCurrentUser(r)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	err = b.srv.Bim().UploadFile(file, user)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	_, _ = helper.WriteJSON(w, server.OK("Upload successfully!"))
}

// TranslateFile 转换文件
func (b *BimHandler) TranslateFile(w http.ResponseWriter, r *http.Request) {
	bimTranslateModel := new(model.BimTranslateModel)
	err := helper.ReadRequestBody(bimTranslateModel, w, r)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	err = helper.GetValidator().Struct(bimTranslateModel)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	callback := fmt.Sprintf("http://%s%s/api/bim/callback", strings.Split(r.Host, ":")[0], server.Config.Server.Port)
	bimTranslateModel.Callback = callback

	user, err := base.GetCurrentUser(r)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	err = b.srv.Bim().TranslateFile(bimTranslateModel, user)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	_, _ = helper.WriteJSON(w, server.OK("File translate successfully!"))

}

// Callback 供 bimface 使用的回调函数
func (b *BimHandler) Callback(w http.ResponseWriter, r *http.Request) {
	fileId := r.FormValue("fileId")
	thumbnail := r.FormValue("thumbnail")
	status := r.FormValue("status")
	reason := r.FormValue("reason")
	nonce := r.FormValue("nonce")
	signature := r.FormValue("signature")

	defer func() {
		w.WriteHeader(http.StatusOK)
	}()

	if !b.checkSignature(fileId, status, nonce, signature) {
		//return
	}

	if status != "success" {
		server.Logger.Errorf("file translate failed, fileId: %s, reason: %s", fileId, reason)
		return
	}

	// 更新数据库，并推给前端
	//fmt.Println(thumbnail)
	thumb := strings.Split(thumbnail, ",")
	for i := range thumb {
		if !strings.HasPrefix(thumb[i], "http") {
			thumb[i] = "https://m.bimface.com/" + thumb[i]
		}
	}

	err := b.srv.Bim().UpdateFile(&model.BimModel{
		FileId:          fileId,
		TranslateStatus: status,
		Thumbnail:       thumb,
	}, nil)

	if err != nil {
		server.Logger.Errorf("update bim file info failed")
	} else {
		server.Logger.Info("callback processed successfully")
	}
}

func (b *BimHandler) checkSignature(fileId, status, nonce, signature string) bool {
	appKey := server.Config.Bimface.AppKey
	appSecret := server.Config.Bimface.AppSecret

	originStr := fmt.Sprintf("%s:%s:%s:%s:%s", appKey, appSecret, fileId, status, nonce)
	md5 := helper.MD5(originStr)
	return signature == md5
}

func (b *BimHandler) DeleteFile(w http.ResponseWriter, r *http.Request) {
	fileId := r.FormValue("fileId")
	if fileId == "" {
		_, _ = helper.WriteJSON(w, server.Fail("fileId is required."))
		return
	}
	user, err := base.GetCurrentUser(r)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	err = b.srv.Bim().DeleteFile(fileId, user)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	_, _ = helper.WriteJSON(w, server.OK("Delete successfully!"))
}

func (b *BimHandler) GetSupportType(w http.ResponseWriter, r *http.Request) {
	bimResult, err := b.srv.Bim().GetSupportType()
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	_, _ = helper.WriteJSON(w, server.OK("Get successfully!").WithData(bimResult.Data))
}

func (b *BimHandler) ListFile(w http.ResponseWriter, r *http.Request) {
	user, err := base.GetCurrentUser(r)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}

	results, err := b.srv.Bim().ListFile(user)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	_, _ = helper.WriteJSON(w, server.OK("Get successfully!").WithData(results))
}

// ViewToken 获取模型 view token
func (b *BimHandler) ViewToken(w http.ResponseWriter, r *http.Request) {
	fileId := r.FormValue("fileId")
	if fileId == "" {
		_, _ = helper.WriteJSON(w, server.Fail("fileId is required"))
		return
	}
	bimResult, err := b.srv.Bim().ViewToken(fileId)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	_, _ = helper.WriteJSON(w, server.OK("Get successfully!").WithData(bimResult.Data))
}

func (b *BimHandler) FileInfo(w http.ResponseWriter, r *http.Request) {
	fileId := r.FormValue("fileId")
	if fileId == "" {
		_, _ = helper.WriteJSON(w, server.Fail("fileId is required"))
		return
	}
	bimModel, err := b.srv.Bim().FileInfo(fileId)
	if err != nil {
		_, _ = helper.WriteJSON(w, server.Fail(err.Error()))
		return
	}
	_, _ = helper.WriteJSON(w, server.OK("Get successfully!").WithData(bimModel))
}
